package com.chen.blog.config.security;

import com.chen.blog.common.constant.MessageConstant;
import com.chen.blog.config.security.component.JwtAuthenticationTokenFilter;
import com.chen.blog.config.security.component.RestAuthenticationEntryPoint;
import com.chen.blog.model.Admin;
import com.chen.blog.model.User;
import com.chen.blog.service.AdminService;
import com.chen.blog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * @Description SpringSecurity配置类
 * @Author zgyh2
 * @Date 2022/1/24
 * @Version 1.0
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AdminService adminService;

    @Autowired
    private UserService userService;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
        return new JwtAuthenticationTokenFilter();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/admin/login", "/captcha", "/css/**", "/js/**", "/index.html", "favicon.ico", "/doc.html"
                , "/webjars/**", "/swagger-resources/**", "/v2/api-docs/**", "/img/**", "/user/login", "/user/{email}", "/user/resetPwd", "/{currentPage}/{pageSize}"
                , "/collect/{id}/{currentPage}/{pageSize}", "/list/{currentPage}/{pageSize}", "/search/**", "/new/**", "/hot/**", "/comment/{id}/{currentPage}/{pageSize}",
                "/detail/{id}", "/type/blog", "/type/{id}/blog/detail", "/tag/blog", "/tag/blog/{id}", "/tag/{currentPage}/{pageSize}", "/user/info/{id}"
                , "/follow/{currentPage}/{pageSize}","/user/add");
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        //tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //使用JWT，不需要csrf
        http.csrf()
                .disable()
                //基于token，不需要session
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .cors()
                .and()
                //记住我的配置
                // rememberMe需要的配置包含TokenRepository对象以及token过期时间
                .rememberMe()
                .tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(60 * 60 * 24)
                .userDetailsService(userDetailsService())
                .and()
                .authorizeRequests()
                //所有请求都要求认证
                .anyRequest()
                .authenticated()
                .and()
                .headers()
                .cacheControl();
        //添加JWT 登录授权过滤器
        http.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        //添加未登录结果返回
        http.exceptionHandling()
                .authenticationEntryPoint(restAuthenticationEntryPoint);
    }

    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        return username -> {
            Admin admin = adminService.getAdminByUserName(username);
            if (admin != null) {
                return admin;
            }
            User user = userService.getUserByUserName(username);
            if (user != null) {
                return user;
            }
            throw new UsernameNotFoundException(MessageConstant.ADMIN_LOGIN_FAIL);
        };
    }
}
